<?php

namespace common\logics;

use Yii;
use yii\db\Exception;
use common\helpers\IpHelper;
use common\models\user\UserAccount;
use common\models\user\UserAccountLog;

/**
 * 账户积分结算
 *
 * @package common\logics
 * @property null|UserAccount $account
 */
class AccountBalanceLogic extends \common\base\Model {

    //
    const TYPE_EXP = 0;
    const TYPE_CREDIT = 1;
    const TYPE_GOLD = 2;
    const TYPE_CASH = 3;

    //
    const BALANCE_IN = 1;
    const BALANCE_OUT = -1;
    const BALANCE_FROZEN = 0;

    /**
     * @var number 变动金额
     */
    public $value;

    /**
     * @var integer 用户UID
     */
    public $user_id;

    /**
     * @var integer 积分类型
     */
    public $type;

    /**
     * @var integer 结算方式
     */
    public $balance;

    /**
     * @var string 日志备注
     */
    public $mark;

    /**
     * @var UserAccount|null
     */
    private $_account = null;

    /**
     * @var int 结算前账户积分
     */
    private $_original = 0;

    /**
     * {@inheritdoc}
     */
    public function rules() {
        return [
            [['user_id', 'type', 'value', 'balance', 'mark'], 'required'],
            [['user_id', 'type', 'value', 'balance'], 'integer'],
            [['mark'], 'string'],
            ['user_id', 'validateAccount'],
            ['value', 'validateValue'],
        ];
    }

    /**
     * 校验账户信息
     *
     * @param string $attribute
     */
    public function validateAccount($attribute) {
        if ($this->hasErrors()) {
            return;
        }
        $account = UserAccount::findOrNew([
            'user_id' => $this->$attribute,
            'type' => $this->type,
        ]);
        if ($account->isNewRecord) {
            $account->attributes = [
                'current' => 0,
                'amount' => 0,
                'consume' => 0,
                'frozen' => 0,
                'status' => UserAccount::STATUS_ACTIVE,
            ];
        }
        if (!$account->isAvaliable()) {
            return $this->addError($attribute, '当前账户已冻结或者不可用');
        } else {
            $this->_original = $account->current;
            $this->_account = $account;
        }
    }

    /**
     * 校验变动金额
     *
     * @param string $attribute
     */
    public function validateValue($attribute) {
        if ($this->hasErrors()) {
            return;
        }
        $value = intval($this->$attribute);
        if ($value <= 0) {
            return $this->addError($attribute, '账户金额无变化或变化数值无效');
        }
        $account = $this->getAccount();
        if (!$account) {
            return $this->addError($attribute, '账户信息不存在或者不可用');
        }
        $balance = $this->balance;
        if ($balance === static::BALANCE_OUT && $value > $account->current) {
            return $this->addError($attribute, '账户金额不足！');
        }
        if ($balance === static::BALANCE_FROZEN && $value > $account->current) {
            return $this->addError($attribute, '冻结金额已超出账户所拥有金额！');
        }
        if ($balance === static::BALANCE_FROZEN) {
            $account->frozen += $value;
        } elseif ($balance === static::BALANCE_IN) {
            $account->amount += $value;
        } elseif ($balance === static::BALANCE_OUT) {
            $account->consume += $value;
        }
        $current = $account->amount - $account->consume - $account->frozen;
        if ($current > 0) {
            $account->current = $current;
        } else {
            return $this->addError($attribute, '账户金额不足！');
        }
    }

    /**
     * @return UserAccount|null
     */
    public function getAccount() {
        return $this->_account;
    }

    /**
     * @return bool
     */
    public function save() {
        if (!$this->validate()) {
            Yii::error($this->getErrorMsg());
            return false;
        }
        $account = $this->getAccount();
        $log = new UserAccountLog();
        $log->setAttributes([
            'user_id' => $this->user_id,
            'balance' => $this->balance,
            'value' => $this->value,
            'original' => $this->_original,
            'recharge' => 0,
            'trade_id' => 0,
            'mark' => $this->mark,
            'ip' => IpHelper::ip(),
            'status' => UserAccountLog::STATUS_ACTIVE,
        ]);
        $transaction = Yii::$app->db->beginTransaction();
        try {
            if (!$account->save()) {
                throw new Exception($account->getErrorMsg());
            }
            $log->account_id = $account->id;
            if (!$log->save()) {
                throw new Exception($log->getErrorMsg());
            }
            $transaction->commit();
        } catch (Exception $e) {
            $transaction->rollBack();
            Yii::error($e->getMessage());
            return false;
        }
        return true;
    }

}
